﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using eWallet.Security.Cryptography;

namespace eWallet.Data.Local
{
	public partial class eWalletDataSet
	{
		public partial class SecretsRow
		{

			public byte[] EncryptedSecret
			{
				get { return this.BlobsRow.Data; }
				set
				{
					if (null != this.BlobsRow)
					{
						this.BlobsRow.Data = value;
					}
					else
					{
						eWalletDataSet ds = (eWalletDataSet)this.Table.DataSet;
						this.BlobsRow = ds.Blobs.AddBlobsRow(Guid.NewGuid(), value);
					}
				}
			}



			public byte[] DecryptData(ICryptoModule cryptoModule)
			{
				if (null == this.GroupsRow)
					throw new InvalidOperationException("The Groups row for this Secrets row is not available. Cannot decrypt data.");

				var key = this.GroupsRow.DecryptGroupKeyAlgorithm(cryptoModule);
				return new SymmetricKeyCryptoModule(key).Decrypt(this.BlobsRow.Data);
			}

			public string DecryptString(ICryptoModule cryptoModule)
			{
				return Encoding.UTF8.GetString(this.DecryptData(cryptoModule));
			}

			public void EncryptData(byte[] data, ICryptoModule cryptoModule)
			{
				if (null == this.GroupsRow)
					throw new InvalidOperationException("The Groups row for this Secrets row is not available. Cannot encrypt data.");

				this.EncryptData(data, cryptoModule, this.GroupsRow);
			}

			public void EncryptData(string data, ICryptoModule cryptoModule)
			{
				if (string.IsNullOrEmpty(data))
					throw new ArgumentNullException("data");

				this.EncryptData(Encoding.UTF8.GetBytes(data), cryptoModule);
			}

			public void EncryptData(byte[] data, ICryptoModule cryptoModule, eWalletDataSet.GroupsRow group)
			{
				if (null == data)
					throw new ArgumentNullException("data");

				if (null == cryptoModule)
					throw new ArgumentNullException("cryptoModule");

				if (null == group)
					throw new ArgumentNullException("group");

				var alg = group.DecryptGroupKeyAlgorithm(cryptoModule);
				var cipher = new SymmetricKeyCryptoModule(alg).Encrypt(data);

				if (null != this.BlobsRow)
				{
					this.BlobsRow.Data = cipher;
				}
				else
				{
					eWalletDataSet ds = (eWalletDataSet)this.Table.DataSet;
					this.BlobsRow = ds.Blobs.AddBlobsRow(Guid.NewGuid(), cipher);
				}
			}

			public void EncryptData(string data, ICryptoModule cryptoModule, eWalletDataSet.GroupsRow group)
			{
				if (string.IsNullOrEmpty(data))
					throw new ArgumentNullException("data");

				this.EncryptData(Encoding.UTF8.GetBytes(data), cryptoModule, group);
			}

			public IEnumerable<string> GetTags()
			{
				List<string> list = new List<string>();

				var rows = this.GetSecretsTagsRows();
				foreach(var r1 in rows)
				{
					if (null != r1.TagsRow && !list.Contains(r1.TagsRow.Label))
						list.Add(r1.TagsRow.Label);
				}

				list.Sort();
				return list;
			}
			
			/// <summary>
			/// Returns whether the current secret is tagged with the given tag.
			/// </summary>
			/// <param name="tagName">The tag to check.</param>
			public bool IsTaggedWith(string tagName)
			{
				return this.GetTags().Contains(tagName);
			}

			/// <summary>
			/// Returns whether the current secret is tagged with the given tag.
			/// </summary>
			/// <param name="tag">The tag to check.</param>
			public bool IsTaggedWith(eWalletDataSet.TagsRow tag)
			{
				return this.IsTaggedWith(tag.Label);
			}

			public bool IsTaggedWith(IEnumerable<eWalletDataSet.TagsRow> tags)
			{
				return null == tags || tags.All(t => this.IsTaggedWith(t));
			}

		}
	}
}
